#include "parsingargs.h"
#include <list>
#include <stdlib.h>
#include <string.h>

#define ERR_PARA_UNKNOWN -1            //未知参数错误
#define ERR_PARA_NOPARA_HAVE -2        //不能有参数的选项有参数错误
#define ERR_PARA_MUSTHAVE_NOTHAVE -3   //必有参数选项后没有跟参数
#define ERR_PARA_PARSE -4              //参数解析出错
#define ERR_PARA_DUPLICATE -5          //关键字重复
#define ERR_PARA_EMPTY -6              // 没解析到任何参数
#define ERR_PARA_MUSTFOUDN_NOTFOUND -7 //必有关键字没出现
#define ERR_PARA_UNIQ_TWO -8           //唯一关键字和其他关键字同时出现
#define ERR_PARA_NOTALL_ONETIME -9     //不能同时出现的关键字同时出现
#define ERR_PARA_DEPEND -10            //依赖关系错误
#define ERR_PARA_MASTER_TWO -11        //主关键字后出现两个互斥关键字

ParsingArgs::ParsingArgs()
{
}

ParsingArgs::~ParsingArgs()
{
}

bool ParsingArgs::AddArgType(const char *shortName, const char *longName, KeyFlag flag, const char *helpInfo)
{
    if (NULL == longName && NULL == shortName) {
        return false;
    }
    Option tmp;
    tmp.m_longName = longName;
    tmp.m_shortName = shortName;
    tmp.m_flag = flag;
    m_args.push_back(tmp);
    if (NULL != helpInfo) {
        if (!m_helpInfo.empty()) {
            m_helpInfo += "\n";
        }
        m_helpInfo.append(shortName).append(" | --").append(longName);
        m_helpInfo.append("\t\t\t");
        m_helpInfo += helpInfo;
    }
    return true;
}

ParsingArgs::KeyFlag ParsingArgs::GetKeyFlag(const bool &bMustValue, std::string &key) //返回flag，
{
    if (bMustValue) {
        return INVALID_KEY;
    }
    for (size_t i = 0; i < m_args.size(); ++i) {
        std::string shortName = "-";
        std::string longName = "--";
        shortName += m_args[i].m_shortName;
        longName += m_args[i].m_longName;
        if (0 == key.compare(shortName) || (0 == key.compare(longName))) {
            // RemoveKeyFlag(key);
            key = m_args[i].m_shortName;
            return m_args[i].m_flag;
        }
    }
    return INVALID_KEY;
}

void ParsingArgs::RemoveKeyFlag(std::string &word)
{
    if (word.size() >= 2) {
        if (word[1] == '-') {
            word.erase(1, 1);
        }
        if (word[0] == '-') {
            word.erase(0, 1);
        }
    }
}

/* pur @ 从Paras中获取一个单词，自动过滤掉单词前后引号，并实现\对空格和引号的转义
 * para @ Paras 返回第一个单词后的所有内容
 * para @ word 返回第一单词
 * para @ bMustValue 返回是否一定是一个value，（引号内的东西一定是一个value）
 * return @ 成功返回true，false失败
*/
bool ParsingArgs::GetWord(std::string &Paras, std::string &word, bool &bMustValue)
{
    size_t iNotSpacePos = Paras.find_first_not_of(' ', 0); //查找第一个非空格字符位置
    if (iNotSpacePos == std::string::npos) {
        Paras.clear();
        word.clear();
        return true;
    }
    size_t length = Paras.size();
    std::list<char> specialChar;
    int islashPos = -1;
    for (size_t i = iNotSpacePos; i < length; i++) {
        char cur = Paras[i];
        bool bOk = false;
        switch (cur) {
            case ' ':
                if (specialChar.empty()) {
                    if (i != (length - 1)) {
                        Paras = std::string(Paras, i + 1, length - i - 1);
                    } else { //最后一个是空格
                        Paras.clear();
                    }
                    bOk = true;
                } else {
                    if (specialChar.back() == '\\') {
                        specialChar.pop_back();
                    }
                    word.append(1, cur);
                }
                break;
            case '"':
                if (specialChar.empty()) {
                    specialChar.push_back(cur);
                } else if (specialChar.back() == cur) { //找到匹配的括号
                    specialChar.pop_back();
                    bMustValue = true;
                } else if (specialChar.back() == '\\') {
                    word.append(1, cur);
                    specialChar.pop_back();
                } else {
                    word.clear();
                    return false;
                }
                break;
            case '\\':
                if (specialChar.empty()) {
                    specialChar.push_back(cur);
                    islashPos = i;
                } else if (specialChar.back() == '"') {
                    if (i < (length - 1)) {
                        if ('"' == Paras[i + 1] || '\\' == Paras[i + 1]) {
                            specialChar.push_back(cur);
                        } else {
                            word.append(1, cur);
                        }
                    } else {
                        word.clear();
                        return false;
                    }
                } else if ('\\' == specialChar.back()) {
                    word.append(1, cur);
                    specialChar.pop_back();
                } else {
                    word.clear();
                    return false;
                }
                break;
            default:
                word.append(1, Paras[i]);
                if (i == (length - 1)) {
                    bOk = true;
                    Paras.clear();
                }
                break;
        }
        if (bOk) {
            return true;
        }
    } // for end
    if (specialChar.empty()) {
        Paras.clear();
        return true;
    } else {
        return false;
    }
}

bool ParsingArgs::IsDuplicateKey(const std::string &key,
                                 const std::map<std::string, std::vector<std::string>> &result)
{
    if (result.find(key) != result.end()) {
        return true; //关键字重复
    }

    for (size_t i = 0; i < m_args.size(); ++i) {
        if ((key.compare(m_args[i].m_longName) == 0 &&
             result.find(m_args[i].m_shortName) != result.end()) ||
            (key.compare(m_args[i].m_shortName) == 0 &&
             result.find(m_args[i].m_longName) != result.end())) {
            return true;
        }
    }
    return false;
}

int ParsingArgs::CheckRules(const std::map<std::string, std::vector<std::string>> &result,
                            std::string &errInfo)
{
    // 1、先检查必须要有的关键字
    for (size_t i = 0; i < m_mustArgs.size(); ++i) {
        if (result.find(m_mustArgs[i]) == result.end()) {
            errInfo.append("must have ");
            errInfo.append(m_mustArgs[i]);
            errInfo.append(" but not found");
            return ERR_PARA_MUSTFOUDN_NOTFOUND; //必有关键字没出现
        }
    }
    // 2、检查只能唯一出现的关键字
    for (size_t i = 0; i < m_uniqArgs.size(); ++i) {
        if ((result.find(m_uniqArgs[i]) != result.end()) && result.size() > 1) {
            errInfo.append("uniq parameter with other parameter. ");
            return ERR_PARA_UNIQ_TWO; //唯一关键字和其他关键字同时出现
        }
    }
    // 3、检查不能同时出现的关键字
    std::vector<std::vector<std::string>> m_mutexArgs;
    for (size_t i = 0; i < m_mutexArgs.size(); ++i) {
        bool bFind = false;
        for (size_t j = 0; j < m_mutexArgs[i].size(); ++j) {
            if (result.find(m_mutexArgs[i].at(j)) != result.end()) {
                if (bFind) {
                    errInfo.append("mutex parameters appear in one commond.");
                    return ERR_PARA_NOTALL_ONETIME; //不能同时出现的关键字同时出现了
                } else {
                    bFind = true;
                }
            }
        }
    }

    // 4、检查依赖关系
    std::map<std::string, std::list<std::vector<std::string>>>::iterator it;
    for (it = m_dependArgs.begin(); it != m_dependArgs.end(); ++it) {
        if (result.end() != result.find(it->first)) { //发现主关键字
            std::list<std::vector<std::string>>::iterator itList;
            bool bMasterOk = false;
            for (itList = it->second.begin(); itList != it->second.end(); ++itList) {
                std::vector<std::string>::iterator itVec;
                bool bFind = false;
                for (itVec = (*itList).begin(); itVec != (*itList).end(); ++itVec) {
                    if (result.end() == result.find(*itVec)) {
                        if (bFind) {
                            errInfo.append("depend relation is wrong.");
                            return ERR_PARA_DEPEND; //依赖关系错误
                        }
                    } else {
                        bFind = true;
                    }
                }
                if (!bMasterOk) {
                    bMasterOk = bFind;
                } else {
                    if (bFind) {
                        errInfo.append(
                        "after master parameter have two mutex parameters.");
                        return ERR_PARA_MASTER_TWO; //主关键字后出现两个互斥的关键字
                    }
                }
            }
            if (!bMasterOk) {
                errInfo.append("depend relation is wrong.");
                return ERR_PARA_DEPEND; //依赖关系错误
            }
        }
    }
    return 0;
}

int ParsingArgs::Parse(const std::string &Paras,
                       std::map<std::string, std::vector<std::string>> &result,
                       std::string &errPos)
{
    std::string tmpString = Paras;
    if (tmpString.empty()) {
        errPos = "parameter is NULL.";
        return ERR_PARA_EMPTY;
    }
    KeyFlag keyFlag = INVALID_KEY; //参数标识
    std::string sKey;              //短关键字
    bool bFindValue = false;       //是否已经有value
    while (!tmpString.empty()) {
        std::string word = "";

        bool bMustValue = false; //是否一定是value值
        bool bRet = GetWord(tmpString, word, bMustValue);

        if (bRet == false) {
            errPos = tmpString;
            errPos.append("parsing parameter error.");
            return ERR_PARA_PARSE; //参数解析错误
        } else {
            KeyFlag tmpFlag = GetKeyFlag(bMustValue, word);

            if (IsDuplicateKey(word, result)) {
                errPos = tmpString;
                errPos.append("duplicate parameter.");
                return ERR_PARA_DUPLICATE;
            }
            if (!bMustValue && (tmpFlag == INVALID_KEY) && (word.at(0) == '-' ? true : false)) // IsWithKeyFlag(word))
            { //防止出现 -c -f aaa/bbb -m 其中f必须有关键字，-m为非关键字的错误
                errPos = tmpString;
                errPos.append("unknown parameter error.");
                return ERR_PARA_UNKNOWN;
            }
            if (tmpFlag != INVALID_KEY) {
                if (keyFlag == MUST_VALUE && !bFindValue) {
                    errPos = tmpString;
                    errPos.append("parameter must have value but not have.");
                    return ERR_PARA_MUSTHAVE_NOTHAVE;
                }
                keyFlag = tmpFlag;
                std::vector<std::string> tmp;
                sKey = word;
                result[sKey] = tmp;
                bFindValue = false;
            } else {
                switch (keyFlag) {
                    case MAYBE_VALUE:
                    case MUST_VALUE: {
                        std::map<std::string, std::vector<std::string>>::iterator it =
                        result.find(sKey);
                        if (it != result.end()) {
                            it->second.push_back(word);
                            bFindValue = true;
                        } else {
                            errPos = tmpString;
                            errPos.append("unknown parameter error.");
                            return ERR_PARA_UNKNOWN; // 没有发现相关的key
                        }
                    } break;
                    case NO_VALUE:
                        errPos = tmpString;
                        errPos.append("parameter not have value but have a value.");
                        return ERR_PARA_NOPARA_HAVE; //不能有参数的选项后有参R_PARA_NOPARA_HAVE
                    default:
                        errPos = tmpString;
                        errPos.append("unknown parameter error.");
                        return ERR_PARA_UNKNOWN; //参数错误
                }                                // switch end
                keyFlag = INVALID_KEY;
            }
        }
    } // while end

    if (keyFlag == MUST_VALUE) {
        errPos.append("parameter must have a value but not have anynoe.");
        return -1; //必有参数后无参数
    }

    return CheckRules(result, errPos);
}

int ParsingArgs::Parse(int argc,
                       char **argv,
                       std::map<std::string, std::vector<std::string>> &result,
                       std::string &errPos)
{
    std::string tmpPara;
    for (int i = 1; i < argc; ++i) {
        if (strlen(argv[i]) == 0) //处理空字符串
        {
            tmpPara += char(31);
        } else {
            tmpPara += argv[i];
        }
        tmpPara += " ";
    }
    return Parse(tmpPara, result, errPos);
}

std::vector<std::string> ParsingArgs::Split(const std::string &str, const std::string &pattern)
{
    std::string::size_type pos;
    std::vector<std::string> result;
    std::string tmp = str;
    tmp += pattern;
    size_t size = tmp.size();
    for (size_t i = 0; i < size; i++) {
        pos = tmp.find(pattern, i);
        if (pos < size) {
            std::string s = tmp.substr(i, pos - i);
            if (!s.empty()) {
                result.push_back(s);
            }
            i = pos + pattern.size() - 1;
        }
    }
    return result;
}
/* pur @ 设置只能唯一出现的短关键字
 * para @ uniqs 短关键字序列，用冒号分隔多个短关键字
 */
void ParsingArgs::SetUniqArgs(const std::string &uniqs)
{
    m_uniqArgs = Split(uniqs, ":");
}

/* pur @ 设置不能同时出现的短关键字
 * para @ mutexes 互斥的短关键字序列，用冒号分隔多个短关键字
 */
void ParsingArgs::SetMutexArgs(const std::string &mutexes)
{
    std::vector<std::string> vec = Split(mutexes, ":");
    if (vec.size() > 0)
        ;
    {
        m_mutexArgs.push_back(vec);
    }
}

/* pur @ 设置不同短关键字间的依赖关系
 * para @ master 主短关键字，
 * para @ slave 从短关键字
 * return @
 */
void ParsingArgs::SetDependence(const std::string &master, const std::string &slave)
{
    if (m_dependArgs.find(master) == m_dependArgs.end()) {
        std::list<std::vector<std::string>> tmpList;
        m_dependArgs[master] = tmpList;
    }
    std::map<std::string, std::list<std::vector<std::string>>>::iterator it =
    m_dependArgs.find(master);

    std::vector<std::string> vec = Split(slave, "&");

    std::vector<std::string> vecList;
    for (size_t i = 0; i < vec.size(); ++i) {
        std::vector<std::string> vecO = Split(vec[i], "|");
        if (vecO.size() == 1) {
            vecList.push_back(vecO[0]);
        } else if (vecO.size() > 1) {
            vecList.push_back(vecO[0]);
            it->second.push_back(vecList);
            vecList.clear();
            vecList.push_back(vecO[1]);
        }
    }
    it->second.push_back(vecList);
    vecList.clear();
    std::vector<std::string>(vecList).swap(vecList); //释放vector的空间
}

void ParsingArgs::SetNecessaryArgs(const std::string &keys)
{
    m_mustArgs = Split(keys, ":");
}
